
#ifndef SKEY_H 
#define SKEY_H 

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include "system/includes.h"
#include "btstack/btstack_task.h"
#include "app_config.h"
#include "app_action.h"
#include "gpadc.h"
#include "app_tone.h"
#include "gpio_config.h"
#include "app_main.h"
#include "asm/charge.h"
#include "update.h"
#include "app_power_manage.h"
#include "audio_config.h"
#include "app_charge.h"
#include "bt_profile_cfg.h"
#include "update_loader_download.h"
#include "idle.h"
#include "bt_tws.h"
#include "key_driver.h"
#include "adkey.h"
#include "user_cfg.h"
#include "usb/device/usb_stack.h"
#include "usb/usb_task.h"
#include "dev_manager.h"
#include "vm.h"
#include "iokey.h"
#include "asm/lp_touch_key_api.h"
#include "fs/sdfile.h"
#include "utils/syscfg_id.h"
#include "asm/power_interface.h"
#include "app_default_msg_handler.h"
#include "earphone.h"
#include "usb/otg.h"
/*-----------------------------------macro------------------------------------*/
/**
 * @brief ## Switch macro table
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */

/**
 * @brief  allow creat multiple skey check member list with different scan period
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
// #define SKEY_USE_MULTI_SCANNER


#ifdef SKEY_USE_MULTI_SCANNER
#define SKEY_DEFAULT_SCAN_PERIOD 30
#endif

/*----------------------------------typedef-----------------------------------*/
typedef enum {
    KEY_TRIGGER_UNSUPPORT = 0x00,
    KEY_TRIGGER_HIGH = 0x01,
    KEY_TRIGGER_LOW = 0x02,

    KEY_TRIGGER_PRESSED = 0x04,
    KEY_TRIGGER_RELEASED = 0x08,
    KEY_TRIGGER_CLICK = 0x10,
    KEY_TRIGGER_DOUBLE_CLICK  = 0x20,
    KEY_TRIGGER_TRIPLE_CLICK  = 0x40,
    KEY_TRIGGER_QUADRA_CLICK  = 0x80,

    KEY_TRIGGER_HOLD_0 = 0x0100,
    KEY_TRIGGER_HOLD_1 = 0x0200,
    KEY_TRIGGER_HOLD_2 = 0x0400,
    KEY_TRIGGER_HOLD_3 = 0x0800,
}keyTriggerTypeDef;

typedef struct key_check_member
{
    struct list_head list; //链表头，内部使用
    uint16_t combo_count; // 连击数，内部使用
    uint8_t key_last_state; //上次状态，内部使用，消抖处理
    uint8_t key_last_state_temp; //上次状态，内部使用，消抖处理
    uint8_t combo_timeout; // 两次按键的最长间隔，初始化时设置，单位为tick
    uint8_t key_hold_trigger_state; // 按键按下状态，内部使用,记录各个按键状态
    uint32_t key_trigger_type;      // 激活的触发条件，初始化时设置,多个条件用|号分隔
    uint16_t key_hold_time_counter; // 当前长按计时，内部使用
    uint16_t key_hold_time_check[4];// 设定长按触发时间,0-3对应HOLD_0-HOLD_3时间的时间，初始化时设置
    int (*getPortValueCallback)(void *port_info); // 按键值回调，要求0为Press,1为Release，初始化时设定
    int (*portInitCallback)(void *port_info);     // 按键初始化回调，初始化时设定，若不需要初始化传NULL
    void *port_info;                              // 按键信息，传(void*)指针，传入能表示IO的变量。回调中处理即可，初始化时设定
    void (*trigger_callback)(void *p, keyTriggerTypeDef signal); // 有触发事件时的回调函数，p为sender，也就是结构体本身的指针，signal为触发的信号，连击时连击数会被按位或至低四位，初始化时设定
    void *private_data;                                          // 其它参数，回调用不上就不用传，初始化时设置
}key_check_member_t;

#define for_each_key_node(key_node,p_member_list) \
for(key_node = (key_check_member_t*)(((key_check_member_t*)(p_member_list))->list.next); \ 
&(key_node->list) != &(p_member_list->list); \
key_node = (key_check_member_t*)(((struct list_head*)key_node)->next))

#define KEY_CHECK_MEMBER_REGISTER(key_member_name) \
static key_check_member_t _key_check_member_##key_member_name __attribute__((used,__section__(".key_check_member")))

#define KEY_CHECK_DEFAULT_COMBO_TICK 7
#define KEY_CHECK_MS_TO_TICK(x) (x/30)

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
 * @brief When a event triggers,the message will be sent by this function
 * @param  sender           key_check_member_t * the key member whose event were triggered
 * @param  TriggerSignal    int32_t the signal triggered,note:if event is hold,this signal = KEY_CHECK_TRIGGER_HOLD_x + combo count(x=HOLD type id,combo count < 256)
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
void key_send_message(key_check_member_t* sender,int32_t TriggerSignal);
#ifdef SKEY_USE_MULTI_SCANNER
/**
 * @brief init a key check driver
 * @param  key_check_member_list the list used to manager key scan,you can creat a null struct,and put its pointer in.
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
void key_check_init(struct list_head * key_check_member_list, u32 scan_period);
#else
/**
 * @brief init a key check driver
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */
void key_check_init(void);
#endif
int getPortValue(void *port_info);
int portInit(void *port_info);

/*------------------------------------test------------------------------------*/
#ifdef __cplusplus
}
#endif

#endif	/* SKEY_H */